package com.lkd.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lkd.http.view.TokenObject;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.Data;

import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.Date;
import java.util.Map;

public class JWTUtil {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 签发 JWT
     */
    public static String createJWTByObj(TokenObject tokenObject, String secret)  {
        // 1. 解码 Base64 密钥并生成 SecretKey
        byte[] keyBytes = Decoders.BASE64.decode(secret);
        SecretKey key = Keys.hmacShaKeyFor(keyBytes);

        // 2. 设置过期时间（7天）
        Instant now = Instant.now();
        Instant expiresAt = now.plusSeconds(7 * 24 * 3600); // 7天 = 604800 秒

        // 3. 将 tokenObject 转为 Map（关键修复！）
        @SuppressWarnings("unchecked")
        Map<String, Object> claims = MAPPER.convertValue(tokenObject, Map.class);

        // 4. 构建 JWT（无需手动设置 typ/alg，JJWT 会自动添加）
        return Jwts.builder()
                .id("lkd")
                .issuedAt(Date.from(now))
                .expiration(Date.from(expiresAt))
                .claims(claims)
                .signWith(key, Jwts.SIG.HS256)
                .compact();
    }

    /**
     * 验证 JWT
     */
    public static VerifyResult verifyJwt(String token, String secret) {
        try {
            byte[] keyBytes = Decoders.BASE64.decode(secret);
            SecretKey key = Keys.hmacShaKeyFor(keyBytes);

            // 使用 JJWT 0.12+ 的新解析方式
            Jws<Claims> jwt = Jwts.parser()
                    .verifyWith(key) // 替代 setSigningKey
                    .build()
                    .parseSignedClaims(token); // 替代 parse()

            Claims claims = jwt.getPayload();
            Date expiration = claims.getExpiration();

            if (expiration == null || expiration.before(new Date())) {
                return new VerifyResult(false, 5001); // 过期
            }

            // 可选：反序列化 claims 回 TokenObject
            TokenObject tokenObject = MAPPER.convertValue(claims, TokenObject.class);

            return new VerifyResult(true, 200, tokenObject);

        } catch (ExpiredJwtException e) {
            return new VerifyResult(false, 5001);
        } catch (JwtException | IllegalArgumentException e) {
            return new VerifyResult(false, 5002);
        }
    }

    /**
     * （可选）直接解码 payload（不验证签名）
     */
    public static TokenObject decode(String token) throws Exception {
        String[] chunks = token.split("\\.");
        String payload = new String(Decoders.BASE64URL.decode(chunks[1]));
        return MAPPER.readValue(payload, TokenObject.class);
    }

    @Data
    public static class VerifyResult {
        private boolean isValidate;
        private int code; // 5001:过期; 5002:无效; 200:成功
        private TokenObject tokenObject;

        public VerifyResult(boolean isValidate, int code) {
            this(isValidate, code, null);
        }

        public VerifyResult(boolean isValidate, int code, TokenObject tokenObject) {
            this.isValidate = isValidate;
            this.code = code;
            this.tokenObject = tokenObject;
        }
    }
}